home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / allswags.zip / FAQ.SWG < prev    next >
Text File  |  1993-05-28  |  110KB  |  1 lines

  1. SWAGOLX.EXE (c) 1993 GDSOFT  ALL RIGHTS RESERVED 00004         FREQUENTLY ASKED QUESTIONS                                        1      05-28-9313:45ALL                      SWAG SUPPORT TEAM        A2FAPQ.FAQ               IMPORT              289                 ANSWERS TO FREQUENTLY ASKED PASCAL QUESTIONSπ        ============================================ππ1...π                                                                              π  Q. How do I pass an error level code when my program finishes?              π                                                                              π  A. The halt procedure takes an optional parameter of type word. Thus -      π                                                                              π         halt(1);                                                             π                                                                              π     terminates the program with an errorlevel of 1.  If halt is used without π     a parameter it is the same as -                                          π                                                                              π         halt(0);                                                             π                                                                              π     Note:  When a program is terminated using the halt procedure any exit    π            procedure that has previously been set up is executed.            πππ2...π                                                                          π  Q. How do I empty the keyboard buffer?                                      π                                                                              π  A. There are several ways that this can be achieved.  However the safest    π     is -                                                                     π                                                                              π        while Keypressed do ch := ReadKey;                                    π                                                                              π     This requires that a variable ch of type char is declared and the crt    π     unit be used.  To do it without using a variable -                       π                                                                              π       while Keypressed do while ReadKey = #0 do;                             π                                                                              π     or if using TP6 with extended syntax enabled -                           π                                                                              π        while KeyPressed do ReadKey;                                          π                                                                              π     If you do not wish to incur the substantial overhead involved with the   π     use of the CRT unit and there is no requirement for the program to run   π     under a multi-tasker -                                                   π                                                                              π        var                                                                   π          head : byte absolute $40:$1c;                                       π          tail : byte absolute $40:$1e;                                       π                                                                              π        tail := head;                                                         ππ3...ππ  Q. When I redirect the screen output of my programs to a file the file is   π     empty and the output still appears on the screen. What am I doing        π     wrong?                                                                   π                                                                              π  A. You are probably using the CRT unit and its default method of writing    π     to stdout is by direct screen writes.  In order to enable output to be   π     redirected all writes must be done by DOS.  Setting the variable         π     DirectVideo to false has no effect on redirection as all it does is use  π     the BIOS for screen writes - not DOS.                                    π                                                                              π     To enable redirection you must not use the CRT unit                      π                                                                              π     OR                                                                       π                                                                              π     assign(output,'');                                                       π     rewrite(output);                                                         π                                                                              π     This will make all output go through DOS and thus can be redirected if   π     desired.  To restore the default situation -                             π                                                                              π     AssignCRT(output); rewrite(output);                                      πππ4...ππ   Q. How do I make a string that is lower or mixed case all uppercase?π                                                                              π   A. There are several ways to convert lower case characters to upper case.  π      Here are some of them.                                                  π                                                                              π      As a procedure (excluding asm code this is the fastest way)             π                                                                              π        procedure StrUpper(var st: string);                                   π          var x : byte;                                                       π          begin                                                               π            for x := 1 to length(st) do                                       π              st[x] := UpCase(st[x]);                                         π          end;                                                                π                                                                              π      As a function (slower but sometimes more convenient) -                  π                                                                              π        function StrUpper(st: string): string;                                π          var x : byte;                                                       π          begin                                                               π            StrUpper[0] := st[0];                                             π            for x := 1 to length(st) do                                       π              StrUpper[x] := UpCase(st[x]);                                   π          end;                                                                π                                                                              π      Both the above are suitable for the English language .  However from    π      version 4.0 onwards, DOS has had the facility to do this in a way that  π      is country (language) specific.  I am indebted to Norbert Igl for the   π      basic routine.  I have modified his code slightly.  For the anti-goto   π      purists this is a good example of a goto that is convenient, efficient, π      self-documenting and structured.  The dos calls would make this method  π      the slowest of all.                                                     π                                                                              π     function StrUpper(s: string): string;                                    π       { Country specific string-to-uppercase conversion. Requires DOS unit } π       label                                                                  π         fail;                                                                π       var                                                                    π         regs : registers;                                                    π         x    : byte;                                                         π       begin                                                                  π         if lo(DosVersion) >= 4 then begin                                    π           with regs do begin                                                 π             ax := $6521;                                                     π             ds := seg(s);                                                    π             dx := ofs(s[1]);                                                 π             cx := length(s);                                                 π             msdos(regs);                                                     π             if odd(flags) then { the attempted conversion failed so }        π               goto fail;                                                     π           end; { with }                                                      π         end { if DOS >= 4.0 } else                                           π       fail:                                                                  π           for x := 1 to length(s) do                                         π             s[x] := UpCase(s[x]);                                            π         StrUpper := s;                                                       π       end; { StrUpper }                                                      ππππ5...π                                                                              π   Q. When I include ANSI codes in a string and write that string to the      π      screen the actual codes appear on the screen, rather than the results   π      they are supposed to achieve.                                           π                                                                              π   A. In order for ANSI codes to be interpreted, screen writes must be        π      directed through DOS and there must have been a suitable driver loaded  π      via the config.sys file at boot time.  All output can be directed       π      through DOS and the driver by -                                         π                                                                              π      Not using the crt unit                                                  π                                                                              π      OR -                                                                    π                                                                              π      assign(output,'');                                                      π      rewrite(output);                                                        π                                                                              π      in which case ALL screen writes are "ANSI code sensitive"               π                                                                              π      OR -                                                                    π                                                                              π      You can set up write procedures that will be "ANSI code sensitive".     π      (You will need an initialisation procedure to set this up.)             π                                                                              π      var                                                                     π        ansi : text;                                                          π                                                                              π      procedure AssignANSI(var ansifile : text);                              π        begin                                                                 π          assign(ansifile,'CON');                                             π          rewrite(ansifile);                                                  π        end; { AssignANSI }                                                   π                                                                              π      procedure WriteANSI(var st: string);                                    π        begin                                                                 π          write(ansi,st)                                                      π        end; { WriteANSI }                                                    π                                                                              π      procedure WriteLnANSI(var st: string);                                  π        begin                                                                 π          writeANSI(st);                                                      π          writeln(ansi);                                                      π        end; { WriteANSI }                                                    π                                                                              π      ObviousLy, if the ANSI.SYS driver (or an equivalent) is not installed   π      none of the above can work.                                             π                                                                              π      Setting the variable DirectVideo in the CRT unit to false will not      π      achieve the desired result as this merely turns off direct screen       π      writes and uses the BIOS for all screen output.                         πππ6...π                                                                              π   Q. When I try to shell to DOS nothing happens. What am I doing wrong?      π                                                                              π   A. In order to be able to execute any child process there must be          π      sufficient memory available for it to load and execute.  Unless you     π      advise differently at compile time, a Turbo Pascal program grabs all    π      available memory for itself when it is loaded.  To reserve memory for a π      child process use the compiler memory directive -                       π                                                                              π        {$M 16384,0,0)                                                        π      the default is -                                                        π        {$M 16384,0,655360}                                                   π                                                                              π      The first figure - StackMin - is the amount of memory to be allocated   π      for the stack:                                                          π                                                                              π      Minimum is:    1024                                                     π      Default is:   16384                                                     π      Maximum is:   65520                                                     π                                                                              π      The next figure - HeapMin -is the minumum amount of memory to be        π      allocated for the heap. If there is less memory available than this     π      figure the program will not load.                                       π                                                                              π      Minimum is:          0                                                  π      Default is:          0                                                  π      Maximum is:     655360  In practice it will be the amount of free       π                              memory less the space required for the stack,   π                              less the code space of the program.  You should π                              set this to 0 unless your program uses the      π                              heap.  In that case, set it to the lowest       π                              possible figure to prevent heap allocation      π                              errors.  In most cases it is best to leave it   π                              at zero and do error checking within the        π                              program for sufficient memory at allocation     π                              time.                                           π                                                                              π      The last figure is the crucial on as regards child processes.  It       π      should always be low enough to leave memory left over for a child       π      process and high enough not to cause problems for the program when      π      allocating heap memory.                                                 π                                                                              π      Minimum is:  HeapMin                                                    π      Default is:  655360                                                     π      Maximum is:  655360     If less than the requested amount is available  π                              no error is reorted.  Instead all available     π                              memory is allocated for heap use.               ππππ7...π                                                                              π   Q. How do I shell to DOS?                                                  π                                                                              π   A. SwapVectors;                                                            π      exec(GetEnv('COMSPEC','');                                              π      SwapVectors;                                                            π                                                                              π      Read previous section on memory allocation.                             π                                                                              π      I find that it is a good idea to write my own Exec function which will  π      do everything that is needed for me.  I have it return an integer value π      that is the DosError code.                                              π                                                                              π      function Exec(p1,p2: string);                                           π        begin                                                                 π          SwapVectors;                                                        π          Dos.Exec(p1,p2);                                                    π          SwapVectors;                                                        π          Exec := DosError;                                                   π        end;                                                                  π                                                                              π      This enables me to have a statement such as -                           π                                                                              π      ReportError(Exec(GetEnv('COMPSEC'),''));                                π                                                                              π      Now you can have an empty ReportError procedure or you can make it      π      report the error - whatever is suitable for you application.            πππ8...π                                                                              π   Q. When I execute a child process redirection does not work. Why?          π                                                                              π   A. Redirection of a child process's output only works if it is run under   π      another copy of the command processor.  So -                            π                                                                              π      exec('YourProg.exe',' > nul');    will not work but                     π      exec(GetEnv('COMSPEC'),'/c YourProg > nul'); will work.                 πππ9...ππ   Q. How do I read an errorlevel from a child process?ππ   A. After executing a child process the errorlevel returned can be readπ      by calling the DosExitCode function which returns a word.  The lowπ      byte is the errorlevel.  A full description is in the manual.ππ      If the command interpreter is the child process and it in turnπ      executes a child process then the errorlevel of the second childπ      process cannot be read without resorting to some trickery.πππ10...ππ   Q. When I read a text file that has lines exceeding 255 characters Iπ      lose all those characters from the 256th one on each time there is aπ      line that exceeds that length.  How can I prevent this?ππ   A. Turbo Pascal's readln procedure reads a line up to the 255thπ      character then skips to the next line.  To get around this youπ      should declare a buffer at least as large as the longest possibleπ      line and then use the read procedure.  The best size for the bufferπ      is a multiple of 2048 bytes.ππ      constπ        BufferSize = 2048;π        LineLength = 78;π      typeπ        textbuffer = array[1..BufferSize] of char;π      varπ        st          : string;π        f           : text;π        buffer      : textbuffer;ππ      function ReadTxtLn(var tf: text; var s: string; max: byte): integer;π        { Reads a string of a maximum length from a text file }π        varπ          len         : byte absolute s;π        beginπ          len := 0;π          {$I-}π          while (len < max) and not eoln(tf) do beginπ            inc(len);π            read(tf);π          end;π          if eoln(tf) thenπ            readln(tf);π          ReadTxtLn := IOResult;π          {$I+}π        end; { ReadTxtLn }ππ      beginπ        assign(f,filename);π        reset(f);π        SetTextBuf(f,buffer);π        while not eof(f) and (ReadTxtLn(f,st,LineLength) = 0) doπ          writeln(st);π        close(f);π      end.πππ11...ππ   Q. How do I convert nul terminated asciiz strings to Turbo Pascalπ      strings?ππ   A. Here is a function that will do that -ππ      function Asc2Str(var s; max: byte): string;π        { Converts an ASCIIZ string to a Turbo Pascal string }π        { with a maximum length of max.                      }π        var starray  : array[1..255] of char absolute s;π            len      : integer;π        beginπ          len        := pos(#0,starray)-1;              { Get the length }π          if (len > max) or (len < 0) then      { length exceeds maximum }π            len      := max;                         { so set to maximum }π          Asc2Str    := starray;π          Asc2Str[0] := chr(len);                           { Set length }π        end;  { Asc2Str }πππ12...ππ   Q. How can I tell if a particular bit of a variable is set or not? How canπ      I set it?  How can I turn it off? How can I make a large bit map andπ      then determine if a particular bit - say bit 10000 is on/of?ππ   A. This question, or a variation of it, is one of the most commonly askedπ      questions in the echo and there are several ways of doing what isπ      wanted.  None are necessarily right or wrong.  The way I will describeπ      is designed to take up as little code/data space as possible.  I do notπ      attempt to explain the theory behind these functions as this can beπ      obtained from any good book. Question 16 also contains valuable extraπ      help on the subject of truth tables.ππ      The use of sets can be the best bit manipulation method if you haveπ      control over the data being used. Here is an example of a byte variableπ      for a BBS program which sets various user access level flags.ππ         Bit 0 = Registered Userπ             1 = Twitπ             2 = Normalπ             3 = Extraπ             4 = Privilegedπ             5 = Visiting Sysopπ             6 = Assistant Sysopπ             7 = Sysopππ       typeπ         status_type  = (Registered,π                         Twit,π                         Normal,π                         Extra,π                         Privileged,π                         VisitingSysop,π                         AssistantSysop,π                         Sysop);π          status_level = set of status_type;ππ       varπ         access_flags  : status_level;ππ      Let us assume you have someone who logs on and you wish to determineπ      his user access level.  After reading access_flags from the user dataπ      file -ππ           if Sysop in access_flags then ....ππ      To set the sysop flag -ππ           access_flags := access_flags + [Sysop];ππ      To reset the sysop flag -ππ           access_flags := access_flags - [Sysop];ππ      However on many occasions using a set may not be a suitable method.π      You may simply need to know if bit 5 is set or not.  Here is the methodπ      that I consider the best -ππ        function BitIsSet(var V,  bit: byte): boolean;π          beginπ            BitIsSet := odd(V shr bit);π          end;ππ      To set a bit -ππ         procedure SetBit(var V: byte; bit: byte);π           beginπ             V := V or (1 shl bit);π           end;ππ      To reset a bit -ππ         procedure ResetBit(var V: byte; bit: byte);π           beginπ             V := V and not(1 shl bit);π           end;ππ      To toggle (flip) a bit -ππ         procedure ToggleBit(var V: byte; bit: byte);π           beginπ             V := V xor (1 shl bit);π           end;ππ      Now a bit map can be made up from an array of bytes.  If stored on theπ      heap you can test any bit up to number 524159 (zero based).  Here'sπ      how.ππ      typeπ        map = array[0..maxsize] of byte;π        { set maxsize to number of bits div 8 -1 needed in the bit map }ππ      function BitSetInBitMap(var x; numb : longint): boolean;π        { Tests the numb bit in the bitmap array }π        var m: map absolute x;π        beginπ          BitSetInBitMap := odd(m[numb shr 3] shr (numb and 7));π        end;ππ      procedure SetBitInBitMap(var x; numb: word);π        { Sets the numb bit in the bitmap array }π        var m: map absolute x;π        beginπ          m[numb shr 3] := m[numb shr 3] or (1 shl (numb and 7))π        end;ππ      procedure ResetBitInBitMap(var x; numb : longint);π        { Resets the numb bit in the bitmap array }π        var m: map absolute x;π        beginπ         m[numb shr 3] := m[numb shr 3] and not(1 shl (numb and 7));π        end;ππ      procedure ToggleBitInBitMap(var x; numb : longint);π        { Toggles (flips) the numb bit in the bitmap array }π        var m: map absolute x;π        beginπ          m[numb shr 3] := m[numb shr 3] xor (1 shl (numb and 7));π        end;πππ13...ππ   Q. How can I find a particular string in any file - text or binary?ππ   A. The Boyer-Moore string search algorithm is considered to be the fastestπ      method available.  However in a rare worst-case scenario it can beπ      slightly slower than a linear brute-force method.  The followingπ      demonstration program will show how it works and could easily beπ      modified to allow for command line paramters etc.πππ      program BMSearchDemo;ππ      typeπ        bigarray = array[0..32767] of byte;π        baptr    = ^bigarray;π        BMTable  = array[0..255] of byte;ππ      constπ        KeyStr : string = 'Put whatever you want found here';π        fname  : string = 'f:\Filename.txt';ππ      varπ        Btable : BMtable;π        buffer : baptr;π        f      : file;π        result,π        position : word;π        offset : longint;π        finished,π        Strfound  : boolean;ππ      procedure MakeBMTable(var t : BMtable; var s);π        { Makes a Boyer-Moore search table. s = the search string t = the table }π        varπ          st  : BMtable absolute s;π          slen: byte absolute s;π          x   : byte;π        beginπ          FillChar(t,sizeof(t),slen);π          for x := slen downto 1 doπ            if (t[st[x]] = slen) thenπ              t[st[x]] := slen - xπ        end;ππ      function BMSearch(var buff,st; size : word): word;π        { Not quite a standard Boyer-Moore algorithm search routine }π        { To use:  pass buff as a dereferenced pointer to the buffer}π        {          st is the string being searched for              }π        {          size is the size of the buffer                   }π        { If st is not found, returns $ffff                         }π        varπ          buffer : bigarray absolute buff;π          s      : array[0..255] of byte absolute st;π          len    : byte absolute st;π          s1     : string absolute st;π          s2     : string;π          count,π          x      : word;π          found  : boolean;π        beginπ          s2[0] := chr(len);       { sets the length to that of the search string }π          found := false;π          count := pred(len);π          while (not found) and (count < (size - len)) do beginπ            if (buffer[count] = s[len]) then { there is a partial match } beginπ              if buffer[count-pred(len)] = s[1] then { less partial! } beginπ                move(buffer[count-pred(len)],s2[1],len);π                found := s1 = s2;                   { if = it is a complete match }π                BMSearch := count - pred(len);      { will stick unless not found }π              end;π              inc(count);                { bump by one char - match is irrelevant }π            endπ            elseπ              inc(count,Btable[buffer[count]]);   { no match so increment maximum }π          end;π          if not found thenπ            BMSearch := $ffff;π        end;  { BMSearch }πππ      beginπ        new(buffer);π        assign(f,fname);π        reset(f,1);π        offset := 0;π        MakeBMTable(Btable,KeyStr);π        repeatπ          BlockRead(f,buffer^,sizeof(buffer^),result);π          position := BMSearch(buffer^,KeyStr,result);π          finished := (result < sizeof(buffer^)) or (position <> $ffff);π          if position = $ffff thenπ            inc(offset,result);π          Strfound := position <> $ffff;π        until finished;π        close(f);π        if Strfound thenπ          writeln('Found at offset ',offset)π        elseπ          writeln('Not found');π      end.ππ14...ππ   Q. How can I put a apostrophe in a string?ππ   A. Just put in extra apostrophes.  If you want st to be equal to theπ      string -π        The word 'quoted' is in quotesπ      do this -π        st := 'The word ''quoted'' is in quotes';ππ      if you want the following to be written to screen -π        'This is a quoted string'π      do this -π        writeln('''This is a quoted string''');πππ15...ππ   Q. What are the best books to purchase to help me learn Turbo Pascal?ππ   A. There are many good books for learners.  Here are a few -ππ      Complete Turbo Pascal - Third Edition - Jeff Duntemannπ      Mastering Turbo Pascal 6 - Tom Swannπ      Turbo Pascal - The Complete Reference - O'Brien.ππ      For advanced users there are also many good books.  Here are a fewπ      that I have found useful - (Those marked with an asterisk are notπ      purely for Turbo Pascal)ππ      Turbo Pascal 6 - Techniques and Utilities - Rubenkingπ      Turbo Pascal Internals - Tischerπ      * PC System Programming for Developers - Tischerπ      * Undocumented DOS - Schulmanππ      Any learner would be well advised to obtain a well known libraryπ      such as Technojock's Turbo Toolkit (TTT) which is shareware andπ      study the source code.ππ 16.ππ   Q. hat are "truth tables" and how do they work?ππ   A. Truth tables are a set of rules that are used to determine the result ofπ      logical operations.  The logical operators are -ππ        NOTπ        ANDπ        ORπ        XOR.ππ      Here is a brief explanation of truth tables.  When two values areπ      logically compared by using a logical operator each bit of one value isπ      directly compared to the corresponding bit in the other value and theπ      same bit in the returned value is set or reset according to theπ      following truth table.ππ             NOT         AND             OR            XORπ         not 1 = 0    0 and 0 = 0    0 or 0 = 0    0 xor 0 = 0π         not 0 = 1    0 and 1 = 0    0 or 1 = 1    0 xor 1 = 1π                      1 and 0 = 0    1 or 0 = 1    1 xor 0 = 1π                      1 and 1 = 1    1 or 1 = 1    1 xor 1 = 0ππ      NOT reverses the bit.π      AND sets the returned bit if both compared bits are set.π      OR  sets the returned bit if either of the compared bits are set.π      XOR sets the returned bit if the compared bits are not the same.πππ 17.ππ   Q. What are pointers and how can I use them?  I have heard that they areπ      variables that can be created and discarded as required thus savingπ      memory.  Is this true?ππ   A. A pointer is a variable that contains a memory address.ππ      The heap is all of that memory allocated by DOS to a program for itsπ      use that has not been used by the program for its code, global data orπ      stack.ππ      Dynamic variables are variables that have had space allocated for themπ      on the heap.ππ      Dynamic variables have no identifier (are unnamed).  Because of thisπ      they need an associated variable that can be used to find where theyπ      reside in memory. Pointers are ideal for this but need some method toπ      define what type of data it is that they are pointing at.  Pascalπ      provides this method.ππ        typeπ          Str10Ptr = ^string[10];π          { This means Str10Ptr is a pointer that points to data of type }π          { string[10].                                                  }π        varπ          S : Str10Ptr;ππ      In the above example S is a pointer that has been defined as pointingπ      to an address in memory that will contain (or should contain) data ofπ      type string[10].ππ      However how does S get this value?  How does it know where that data'sπ      address is supposed to be?  Well until the programmer allocates memoryπ      for that data S's value is undefined, so it could be literallyπ      pointing anywhere. So it is *vital* that before we try to use it toπ      use/assign data from/to that memory location we give S a memoryπ      address that is not being used for any other purpose at the moment andπ      that is big enough to hold the data that we want to place into it - inπ      this case at least 11 bytes.  We do this by -ππ        new(S);ππ      Pascal has now allocated at least 11 bytes of heap and has allocated Sπ      with the address of the FIRST byte of that allocation.ππ      Ok... so far so good! How do we access that data (remembering that itπ      has no name).  Well we "dereference" the pointer. This is done byπ      placing a carat sign immediately following the pointer's identifier.ππ        S^ := 'Joe Bloggs';ππ      This statement actually means "Place the string 'Joe Bloggs' into theπ      memory address that S contains". This is referred to as "derferencing"π      the pointer S.ππ      To "reference" a dynamic variable we "dereference" its associatedπ      pointer variable.  We cannot say -ππ        S := 'Joe Bloggs';ππ      because S is a pointer and that would be trying to give a pointer aπ      string type value - a compiler "type mismatch" would occur. So everyπ      time we wish to access that dynamic variable we dereference it.ππ      To delete the dynamic variable once it is of no further use is just aπ      matter of -ππ        dispose(S);ππ      What this statement does is release the memory previously used by S^π      and make it available to be used for other purposes by the program.π      Depending on the version of Pascal you are using it may not erase orπ      alter the contents of that memory and it may not give S a new value.π      However any attempt to dereference S is an error as the integrity ofπ      that memory location has been lost - it may have been allocated toπ      other data.ππ      Pointers do not *have* to point to a memory location in the heap orπ      even have their value always allocated by using the New procedure. Anyπ      valid memory address can be assigned to them and then they can beπ      dereferenced as shown above.  As a simple example of this lets say youπ      want to examine the contents of the 16 byte area at $40:$f0 (the ICAπ      area). You could - (TP specific)ππ         typeπ           ICA_Ptr = ^array[0..15] of byte;π         varπ           B       : byte;π           ICA     : ICA_Ptr;ππ          ICA := ptr($40,$f0);ππ      Now ICA points to the address specified and you can dereference it -ππ          B := ICA^[10];ππ      Hope that helps get you started into the complex world of memoryπ      management and manipulation using pointers.  There are countlessπ      permutations and methods that can be used.πππ 18.ππ   Q. How do I do word wrap?ππ   A. The demo program WRAP.PAS in this archive demonstrates both word wrapπ      and the justifying of text.πππππππππππ                                                                                                  2      05-28-9313:45ALL                      SWAG SUPPORT TEAM        DOS_PGMR.FAQ             IMPORT              491         =====================πsection 1. General questionsπ    101. Why won't my code work?π    102. What is this newsgroup about?π    103. What's the difference from comp.sys.ibm.pc.programmer?π    104. What other newsgroups should I know about?ππsection 2. Compile and linkπ    201. What the heck is "DGROUP > 64K"?π    202. How do I fix "automatic data segment exceeds 64K" or "stackπ         plus data exceed 64K"?π    203. Will Borland C code and Microsoft C code link together?π    204. Why did my program bomb at run time with "floating pointπ         formats not linked"?π    205. Why did my program bomb with "floating point not loaded"?π    206. How can I change the stack size in Borland's C compilers?π    207. What's the format of an .OBJ file?π    208. What's the format of an .EXE header?π    209. What's the difference between .COM and .EXE formats?ππsection 3. Keyboardπ    301. How can I read a character without echoing it to the screen,π         and without waiting for the user to press the Enter key?π    302. How can I find out whether a character has been typed, withoutπ         waiting for one?π    303. How can I disable Ctrl-C/Ctrl-Break and/or Ctrl-Alt-Del?π    304. How can I disable the print screen function?π    305. How can my program turn NumLock (CapsLock, ScrollLock) on/off?π    306. How can I speed up the keyboard's auto-repeat?π    307. What is the SysRq key for?π    308. How can my program tell what kind of keyboard is on the system?π    309. How can I tell if input, output, or stderr has been redirected?ππsection 4. Disks and filesπ    401. What drive was the PC booted from?π    402. How can I boot from drive b:?π    403. Which real and virtual disk drives are valid?π    404. How can I make my single floppy drive both a: and b:?π    405. Why won't my C program open a file with a path?π    406. How can I redirect printer output to a file?π    407. How can my program open more files than DOS's limit of 20?π    408. How can I read, create, change, or delete the volume label?π    409. How can I get the disk serial number?π    410. What's the format of .OBJ, .EXE., .COM files?ππsection 5. Serial ports (COM ports)π    501. How do I set my machine up to use COM3 and COM4?π    502. How do I find the I/O address of a COM port?π    503. But aren't the COM ports always at I/O addresses 3F8, 2F8, 3E8,π         and 2E8?π    504. How do I configure a COM port and use it to transmit data?πsection 6. Other hardware questions and problemsπ    601. Which 80x86 CPU is running my program?π    602. How can a C program send control codes to my printer?π    603. How can I redirect printer output to a file?π    604. Which video adapter is installed?π    605. How do I switch to 43- or 50-line mode?π    606. How can I find the Microsoft mouse position and button status?π    607. How can I access a specific address in the PC's memory?π    608. How can I read or write my PC's CMOS memory?π    609. How can I access memory beyond 640K?πsection 7. Other software questions and problemsπ    701. How can a program reboot my PC?π    702. How can I time events with finer resolution than the systemπ         clock's 55 ms (about 18 ticks a second)?π    703. How can I find the error level of the previous program?π    704. How can a program set DOS environment variables?π    705. How can I change the switch character to - from /?π    706. Why does my interrupt function behave strangely?π    707. How can I write a TSR (terminate-stay-resident) utility?π    708. How can I write a device driver?π    709. What can I use to manage versions of software?π    710. What's this "null pointer assignment" after my C programπ         executes?ππsection A. Downloadingπ    A01. What is garbo?  What is wustl?π    A02. What are Simtel and "mirror sites"?  What good are they?π    A03. Where do I find program <mumble>?π    A04. How can I check Simtel or garbo before I post a request for aπ         program?π    A05. How do I download and decode a program I found?π    A06. Where is UUDECODE?π    A07. Why do I get errors when extracting from a ZIP file Iπ         downloaded?ππsection B. Vendors and productsπ    B01. How can I contact Borland?π    B02. How can I contact Microsoft?π    B03. What's the current version of PKZIP?π    B04. What's in Borland Pascal/Turbo Pascal 7.0?π    B05. What's in Microsoft C/C++ 7.0?πsection C. More informationπ    C01. Are there any good on-line references for PC hardwareπ         components?π    C02. Are there any good on-line references for PC interrupts?π    C03. What and where is "Ralf Brown's interrupt list"?π    C04. Where can I find lex, yacc, and language grammars?π    C05. What's the best book to learn programming?π    C06. Where are FAQ lists archived?π    C07. Where can I get the latest copy of this FAQ list?ππππsection 1. General questionsπ============================ππQ101. Why won't my code work?ππ    First you need to try to determine whether the problem is in yourπ    use of the programming language or in your use of MSDOS and your PCπ    hardware.  (Your manual should tell you which features are standardπ    and which are vendor- or MSDOS- or PC-specific.  You _have_ readπ    your manual carefully, haven't you?)ππ    If the feature that seems to be working wrong is something relatedπ    to your PC hardware or to the internals of MS-DOS, this group is theπ    right place to ask.  (Please check this list first, to make sureπ    your question isn't already answered.)ππ    On the other hand, if your problem is with the programming language,π    the comp.lang hierarchy (including comp.lang.pascal and comp.lang c)π    is probably a better resource.  Please read the other group's FAQπ    list thoroughly before posting.  (These exist in comp.lang.c,π    comp.lang.c++, comp.lang.modula3, comp.lang.lisp, comp.lang.perl;π    they may exist in other groups as well.)  It's almost never a goodπ    idea to crosspost between this group and a language group.ππ    Before posting in either place, try to make your program as small asπ    possible while still exhibiting the bad behavior.  Sometimes thisπ    alone is enough to show you where the trouble is.  Also edit yourπ    description of the problem to be as short as possible.  This makesπ    it look more like you tried to solve the problem on your own, andπ    makes people more inclined to try to help you.ππ    When you do post a question, it's good manners to say "email please;π    I'll post a summary."  Then everybody else in the group doesn't haveπ    to read ten virtually identical responses.  Of course, then you haveπ    to follow through.  A summary is not simply pasting together all theπ    email you received.  Instead, write your own (brief) description ofπ    the solution:  this is the best way to make sure you reallyπ    understand it.  Definitely don't repost people's cute signatures.ππQ102. What is this newsgroup about?ππ    comp.os.msdos.programmer (comp.sys.ibm.pc.programmer until Septemberπ    1990) concerns programming for MS-DOS systems.  The article "USENETπ    Readership report for Nov 92" in news.lists shows 42,000 readers ofπ    this newsgroup worldwide.  Traffic was 1090.7 Kbytes (exclusive ofπ    crossposts), comprised in 611 articles.ππ    Much of our traffic is about language products (chiefly from Borlandπ    and Microsoft).  More programming topics focus on C than on any oneπ    other language.ππ    Since most MS-DOS systems run on hardware that is roughly compatibleπ    with the IBM PC, on Intel 8088, 80188, or 80x86 chips, we tend toπ    get a lot of questions and answers about programming other parts ofπ    the hardware.ππQ103. What's the difference from comp.sys.ibm.pc.programmer?ππ    c.s.i.p.programmer is the old name of comp.os.msdos.programmer, andπ    has been obsolete since September 1990.  However, many systems haveπ    not removed the old group, or have removed it but aliased it to theπ    new name.  This means that some people still think they're postingπ    to c.s.i.p.programmer even though they're actually posting toπ    c.o.m.programmer.ππ    You can easily verify the non-existence of c.s.i.p.programmer byπ    reference to the "List of Active Newsgroups" posted to news.groups.π    It's available as /pub/usenet/news.answers/active-newsgroups/part1π    from the archives (see "Where are FAQ lists archived?" in section C,π    "More information").ππQ104. What other newsgroups should I know about?ππ    Your best bet is to read the periodic information postings in theπ    comp.binaries.ibm.pc newsgroup.  Specially helpful articles:π        Using the comp.binaries.ibm.pc.d groupsπ        Beginner's guide to binariesπ        Starter kitπ        About archives and archiversπ    Please wait for these articles to come around; don't post a request.ππ    Also check out news.announce.newusers, even if you're not a newπ    user.  You may be surprised how much useful information is in theπ    monthly postings there.  Lots of old-timers also get useful stuffπ    from news.newusers.questions, especially the periodic postings.ππ    Remember that it's good manners to subscribe to any newsgroup andπ    read it for a while before you post a question.  When you post, it'sπ    also good manners to ask for replies to be emailed and then to postπ    a summary, which you've edited down to the absolute minimum size.ππ    You may also be interested in the following newsgroups.  Caution:π    Some of them have specialized charters; you'll probably get (andπ    deserve) some flames if you post to an inappropriate group.ππ    - misc.forsale.computers and misc.forsale.computers.pc-clone areπ      where you post notices of equipment, software, or computer booksπ      that you want to sell.  Please don't post or crosspost thoseπ      notices to comp.os.msdos.programmer.ππ    - comp.os.ms-windows.programmer.tools and ...misc (formerly part ofπ      comp.windows.ms.programmer):  Similar to this group, but focusπ      on programming for the MS-Windows platform.ππ    - comp.sys.ibm.pc.hardware is for more hardware-oriented discussionsπ      of the machines that run DOS.ππ    - comp.binaries.ibm.pc.wanted: AFTER you have looked in the otherπ      groups, this is the place to post a request for a particularπ      binary program.ππ    - comp.binaries.msdos.announce (moderated) explains how to use theπ      archive sites, especially garbo and Simtel, and lists filesπ      uploaded to them.  Discussions belong in comp.binaries.msdos.d,π      which replaced comp.binaries.ibm.pc.archives.ππ    - comp.binaries.ibm.pc.d is for discussions about programs posted inπ      comp.binaries.ibm.pc, and only those programs.  This is a goodπ      place to report bugs in the programs, but not to ask where to findπ      them (see cbip.wanted, above).  cbip.d is NOT supposed to be aπ      general PC discussion group.ππ    - comp.sources.misc: a moderated group for source code for manyπ      computer systems.  It tends to get lots of Unix stuff, but you mayπ      also pick up some DOS-compatible code here.ππ    - alt.sources: an unmoderated group for source code.  Guidelines areπ      posted periodically.ππ    - Turbo Vision is a mailing list, not a newsgroup; send email toπ      listserv@vtvm1.cc.vt.edu if you want to subscribe.πππsection 2. Compile and linkπ===========================ππQ201. What the heck is "DGROUP > 64K"?ππ    DGROUP is a link-time group of data segments, and the compilerπ    typically generates code that expects DS to be pointing to DGROUP.π    (Exception: Borland's huge model has no DGROUP.)ππ    Here's what goes into DGROUP:ππ    - tiny model (all pointers near):  DGROUP holds the entire program.ππ    - small and medium models (data pointers near):  DGROUP holds allπ      globals and static variables including string literals, plus theπ      stack and the heap.ππ    - large, compact, and huge models in Microsoft (data pointers far):π      DGROUP holds only initialized globals and static variablesπ      including string literals, plus the stack and the near heap.ππ    - large and compact models in Borland (data pointers far): DGROUPπ      holds initialized and uninitialized globals and static variablesπ      including string literals, but not the stack or heap.ππ    - huge model in Borland (data pointers far): there is no DGROUP, soπ      the 64K limit doesn't apply.ππ    In all of the above, which is to say all six models in Microsoft Cπ    and all but huge in Borland C, DGROUP is limited to 64K includingπ    string literals (which are treated as static data).  This limitationπ    is due to the Intel CPU's segmented architecture.ππ    See the next Q for possible remedies.ππ    For more information, see topics like "memory models" and "memoryπ    management" in the index of your compiler manual.  Also seeπ    TI738.ASC in PD1:<MSDOS.TURBO-C>BCHELP10.ZIP at Simtel for anπ    extended general discussion of memory usage in Borland C programs,π    of which much applies to any C compiler in DOS.ππQ202. How do I fix "automatic data segment exceeds 64K" or "stack plusπ      data exceed 64K"?ππ    These messages are a variation of "DGROUP > 64K".  For causes,π    please see the preceding Q.ππ    If you get this error in tiny model, your program is simply too bigπ    and you must use a different memory model.  If you get this linkπ    error in models S, C, M, L, or Microsoft's H, there are some thingsπ    you can do.  (This error can't occur in Borland's huge model.)ππ    If you have one or two big global arrays, simply declare them far.π    The compiler takes this to mean that any references to them will useπ    32-bit pointers, so they'll be in separate segments and no longerπ    part of DGROUP.ππ    Or you can use the /Gt[number] option with Microsoft or -Ff[=size]π    with Borland C++ 2.0 and up.  This will automatically put variablesπ    above a certain size into their own segments outside of DGROUP.ππ    Yet another option is to change global arrays to far pointers.  Thenπ    at the beginning of your program, allocate them from the far heapπ    (_fmalloc in Microsoft, farmalloc in Borland).ππ    Finally, you can change to huge model (with Borland compilers, notπ    Microsoft).  Borland's H model still uses far pointers by default,π    but "sets aside the [64K] limit" and has no DGROUP group, accordingπ    to the BC++ 2.0 Programmer's Guide.  Microsoft's H model does useπ    huge data pointers by default but retains DGROUP and its 64K limit,π    so switching to the H model doesn't buy you anything if you haveπ    DGROUP problems.ππQ203. Will Borland C code and Microsoft C code link together?ππ    Typically this question is asked by someone who owns compiler A andπ    is trying to write code to link with a third-party library that wasπ    compiled under compiler B.ππ    The answer to the question is, Not in general.  Here are some of theπ    reasons:ππ    - "Helper" functions (undocumented functions for stack checking,π      floating-point arithmetic, and operations on longs) differ betweenπ      the two compilers.ππ    - The compilers may embed instructions in the object code that tellπ      the linker to look for their own run-time libraries.ππ    Those problems will generate link-time errors.  Others may not showπ    up until run time:ππ    - Borland's compact, large, and huge models don't assume DS=SS, butπ      Microsoft's do.  The -Fs option on the Borland compiler, or one ofπ      the /A options on Microsoft, should take care of this problem --π      once you know that's what's going on.ππ    - Check conventions for ordering and packing structure members, andπ      for alignment of various types on byte, word, paragraph, or otherπ      boundaries.  Again, you can generally adjust your code to match ifπ      you know what conventions were used in compiling the "foreign"π      libraries.ππ    - Check the obvious and make sure that your code was compiled underπ      the same memory model as the code you're trying to link with.π      (That's necessary, but no guarantee.  Microsoft and Borland don'tπ      use exactly the same conventions for segments and groups,π      particularly in the larger memory models.)ππ    That said, there are some circumstances where you can link hybrids.π    Your best chance of success comes if you avoid longs and floatingπ    point, use only 16-bit pointers, suppress stack checking, andπ    specify all libraries used in the link.ππQ204. Why did my program bomb at run time with "floating point formatsπ      not linked"?ππ    First, is that the actual message, or did it say "floating point notπ    loaded"?  If it was the latter, see the next Q.ππ    You're probably using a Borland compiler for C or C++ (includingπ    Turbo C and Turbo C++).  Borland's compilers try to be smart and notπ    link in the floating-point (f-p) library unless you need it.  Alas,π    they all get the decision wrong.  One common case is where you don'tπ    call any f-p functions, but you have %f or other f-p formats inπ    scanf/printf calls.  The cure is to call an f-p function, or atπ    least force one to be present in the link.ππ    To do that, define this function somewhere in a source file butπ    don't call it:ππ        static void forcefloat(float *p)π            { float f = *p; forcefloat(&f); }ππ    It doesn't have to be in the module with the main program, as longπ    as it's in a module that will be included in the link.ππ    A new solution for Borland C++ 3.0 was posted, but I don't own theπ    product and have not been able to verify it.  Insert theseπ    statements in your program:ππ        extern unsigned _floatconvert;π        #pragma extref _floatconvertππQ205. Why did my program bomb with "floating point not loaded"?ππ    That is Microsoft C's run-time message when the code requires aπ    numeric coprocessor but your computer doesn't have one installed.ππ    If the program is yours, relink it using the xLIBCE or xLIBCAπ    library (where x is the memory model).ππQ206. How can I change the stack size in Borland's C compilers?ππ    In Turbo C, Turbo C++, and Borland C++, you may not find "stackπ    size" in the index but the global variable _stklen should be there.π    The manual will instruct you to put a statement likeππ        extern unsigned _stklen = 54321U;ππ    in your code, outside of any function.  You must assign the valueπ    right in the extern statement; it won't work to assign a value atπ    run time.  (The "extern" in this context isn't ANSI C and ought notπ    to be required, but the above statement is a direct quote from theπ    Library Reference manual of Borland C++ 2.0.)  The linker may giveπ    you a duplicate symbol warning, which you can ignore.ππQ207. What's the format of an .OBJ file?ππ    Here's what I've been told, though I have verified any of theseπ    references myself:ππ    - base .OBJ format:  Intel's document number #121748-001, {8086π      Relocatable Object Module Formats}.  (Note however that bothπ      Microsoft and Borland formats have extended the .OBJ format.)ππ    - Microsoft-specific .OBJ formats:  a "Microsoft OMF Specification"π      (document number ??), as well as a section in the MS-DOSπ      encyclopedia.ππ    - A "tutorial on the .OBJ format" comes with the VAL experimentalπ      linker, which is VAL-LINK.ARC in PD1:<MSDOS.PGMUTL> at Simtel.ππ    If you have specific references, either to fpt-able documents or toπ    published works (author, title, order number or ISBN), please emailπ    them to brown@ncoast.org for inclusion in the next edition of thisπ    list.ππQ208. What's the format of an .EXE header?ππ    See pages 349-350 of {PC Magazine}'s June 30, 1992 issue (xi:12) forπ    the old and new formats.  For a more detailed layout, look under INTπ    21 function 4B in Ralf Brown's interrupt list.  Ralf Brown's listπ    includes extensions for Borland's TLINK and Borland debugger info.ππ    Among the books that detail formats of executable files are {DOSπ    Programmer's Reference: 2d Edition} by Terry Dettman and Jim Kyle,π    ISBN 0-88022-458-4; and {Microsoft MS-DOS Programmer's Reference},π    ISBN 1-55615-329-5.ππQ209. What's the difference between .COM and .EXE formats?ππ    To oversimplify:  a .COM file is a direct image of core, and an .EXEπ    file will undergo some further relocation when it is run (and so itπ    begins with a relocation header).  A .COM file is limited to 64K forπ    all segments combined, but an .EXE file can have as many segments asπ    your linker will handle and be as large as RAM can take.ππ    The actual file extension doesn't matter.  DOS knows that a fileπ    being loaded is in .EXE format if its first two bytes are MZ or ZM;π    otherwise it is assumed to be in .COM format.  For instance, I amπ    told that DR-DOS 6.0's COMMAND.COM is in .EXE format.πππsection 3. Keyboardπ===================ππQ301. How can I read a character without echoing it to the screen, andπ      without waiting for the user to press the Enter key?ππ    The C compilers from Microsoft and Borland offer getch (or getche toπ    echo the character); Turbo Pascal has ReadKey.ππ    In other programming languages, load 8 in register AH and executeπ    INT 21; AL is returned with the character from standard inputπ    (possibly redirected).  If you don't want to allow redirection, orπ    you want to capture Ctrl-C and other special keys, use INT 16 withπ    AH=10; this will return the scan code in AH and ASCII code (ifπ    possible) in AL, except that AL=E0 with AH nonzero indicates one ofπ    the grey "extended" keys was pressed.  (If your BIOS doesn'tπ    support the extended keyboard, use INT 16 function 0 not 10.)ππQ302. How can I find out whether a character has been typed, withoutπ      waiting for one?ππ    In Turbo Pascal, use KeyPressed.  Both Microsoft C and Turbo C offerπ    the kbhit( ) function.  All of these tell you whether a key has beenπ    pressed.  If no key has been pressed, they return that informationπ    to your program.  If a keystroke is waiting, they tell your programπ    that but leave the key in the input buffer.ππ    You can use the BIOS call, INT 16 function 01 or 11, to checkπ    whether an actual keystroke is waiting; or the DOS call, INT 21π    function 0B, to check for a keystroke from stdin (subject toπ    redirection).  See Ralf Brown's interrupt list.ππQ303. How can I disable Ctrl-C/Ctrl-Break and/or Ctrl-Alt-Del?ππ    You can download the file PD1:<MSDOS.KEYBOARD>CADEL.ZIP from Simtel.π    It contains a TSR to disable those keys, with source code in ASM.ππ    To disable only Ctrl-Alt-Del (actually, to change the boot keys toπ    leftShift-Alt-Del), use DEBOOT.COM.  Along with KEYKILL.COM, whichπ    lets you disable up to three keys of your choice, it is at Simtel inπ    the file PD1:<MSDOS.KEYBOARD>KEYKILL.ARC.ππ    C programmers who simply want to make sure that the user can'tπ    Ctrl-Break out of their program can use the ANSI-standard signal( )π    function; the Borland compilers also offer ctrlbrk( ) for handlingπ    Ctrl-Break.  However, if your program uses normal DOS input, theπ    characters ^C will appear on the screen when the user presses Ctrl-Cπ    or Ctrl-Break.  There are many ways to work around that, including:π    use INT 21 function 7, which allows redirection but doesn't displayπ    the ^C (or echo any other character, for that matter); or use INT 16π    function 0 or 10; or call _bios_keybrd( ) in MSC or bioskey( ) inπ    BC++; or hook INT 9 to discard Ctrl-C and Ctrl-Break before theπ    regular BIOS keyboard handler sees them; etc., etc.ππ    You should be aware that Ctrl-C and Ctrl-Break are processed quiteπ    differently internally.  Ctrl-Break, like all keystrokes, isπ    processed by the BIOS code at INT 9 as soon as the user presses theπ    keys, even if earlier keys are still in the keyboard buffer:  byπ    default the handler at INT 1B is called.  Ctrl-C is not special toπ    the BIOS, nor is it special to DOS functions 6 and 7; it _is_π    special to DOS functions 1 and 8 when at the head of the keyboardπ    buffer.  You will need to make sure BREAK is OFF to prevent DOSπ    polling the keyboard for Ctrl-C during non-keyboard operations.ππ    Some good general references are {Advanced MS-DOS} by Ray Duncan,π    ISBN 1-55615-157-8; {8088 Assembler Language Programming:  The IBMπ    PC}, ISBN 0-672-22024-5, by Willen & Krantz; and {COMPUTE!'s Mappingπ    the IBM PC}, ISBN 0-942386-92-2.ππQ304. How can I disable the print screen function?ππ    There are really two print screen functions:  1) print currentπ    screen snapshot, triggered by PrintScreen or Shift-PrtSc orπ    Shift-grey*, and 2) turn on continuous screen echo, started andπ    stopped by Ctrl-P or Ctrl-PrtSc.ππ    1) Screen snapshot to printerπ       --------------------------ππ    The BIOS uses INT 5 for this.  Fortunately, you don't need to messπ    with that interrupt handler.  The standard handler, in BIOSes datedπ    December 1982 or later, uses a byte at 0040:0100 (alias 0000:0500)π    to determine whether a print screen is currently in progress.  If itπ    is, pressing PrintScreen again is ignored.  So to disable the screenπ    snapshot, all you have to do is write a 1 to that byte.  When theπ    user presses PrintScreen, the BIOS will think that a print screen isπ    already in progress and will ignore the user's keypress.  You canπ    re-enable PrintScreen by zeroing the same byte.ππ    Here's some simple code:ππ        void prtsc_allow(int allow) /* 0=disable, nonzero=enable */ {π            unsigned char far* flag = (unsigned char far*)0x00400100UL;π            *flag = (unsigned char)!allow;π        }ππ    2) Continuous echo of screen to printerπ       ------------------------------------ππ    If ANSI.SYS is loaded, you can easily disable the continuous echo ofπ    screen to printer (Ctrl-P or Ctrl-PrtSc).  Just redefine the keys byπ    "printing" strings like these to the screen (BASIC print, C printf,π    Pascal Write statements, or ECHO command in batch files):ππ        <27>[0;114;"Ctrl-PrtSc disabled"pπ        <27>[16;"^P"pππ    Change <27> in the above to an Escape character, ASCII 27.ππ    If you haven't installed ANSI.SYS, I can't offer an easy way toπ    disable the echo-screen-to-printer function.  Please send any testedπ    solutions to brown@ncoast.org and I'll add them to this list.ππ    Actually, you might not need to disable Ctrl-P and Ctrl-PrtSc.  Ifπ    your only concern is not locking up your machine, when you see theπ    "Abort, Retry, Ignore, Fail" prompt just press Ctrl-P again and thenπ    I.  As an alternative, install one of the many print spoolers thatπ    intercept printer-status queries and always return "Printer ready".ππQ305. How can my program turn NumLock (CapsLock, ScrollLock) on or off?ππ    You need to twiddle bit 5, 6, or 4 of location 0040:0017.  Here'sπ    some code:  lck( ) turns on a lock state, and unlck( ) turns it off.π    (The status lights on some keyboards may not reflect the change.  Ifπ    yours is one, call INT 16 function 2, "get shift status", and thatπ    may update them.  It will certainly do no harm.)ππ        #define NUM_LOCK  (1 << 5)π        #define CAPS_LOCK (1 << 6)π        #define SCRL_LOCK (1 << 4)π        void lck(int shiftype) {π            char far* kbdstatus = (char far*)0x00400017UL;π            *kbdstatus |= (char)shiftype;π        }π        void unlck(int shiftype) {π            char far* kbdstatus = (char far*)0x00400017UL;π            *kbdstatus &= ~(char)shiftype;π        }ππQ306. How can I speed up the keyboard's auto-repeat?ππ    The keyboard speed has two components: delay (before a key that youπ    hold down starts repeating) and typematic rate (the speed once theπ    key starts repeating).  Most BIOSes since 1986 let software changeπ    the delay and typematic rate by calling INT 16 function 3, "setπ    typematic rate and delay"; see Ralf Brown's interrupt list.  If youπ    have DOS 4.0 or later, you can use the MODE CON command that you'llπ    find in your DOS manual.ππ    On 83-key keyboards (mostly XTs), the delay and typematic rate can'tπ    easily be changed.  According to the {PC Magazine} of 15 Jan 1991,π    page 409, to adjust the typematic rate you need "a memory-residentπ    program which simply '[watches]' the keyboard to see if you'reπ    holding down a key ... and after a certain time [starts] stuffingπ    extra copies of the held-down key into the buffer."  No source codeπ    is given in that issue; but I'm told that the QUICKEYS utility thatπ    {PC} published in 1986 does this sort of watching; you can downloadπ    source and object code in PD1:<MSDOS.PCMAG>VOL5N05.ARC from Simtel.ππQ307. What is the SysRq key for?ππ    There is no standard use for the key.  The BIOS keyboard routines inπ    INT 16 simply ignore it; therefore so do the DOS input routines inπ    INT 21 as well as the keyboard routines in libraries supplied withπ    high-level languages.ππ    When you press or release a key, the keyboard triggers hardware lineπ    IRQ1, and the CPU calls INT 9.  INT 9 reads the scan code from theπ    keyboard and the shift states from the BIOS data area.ππ    What happens next depends on whether your PC's BIOS supports anπ    enhanced keyboard (101 or 102 keys).  If so, INT 9 calls INT 15π    function 4F to translate the scan code.  If the translated scan codeπ    is 54 hex (for the SysRq key) then INT 9 calls INT 15 function 85π    and doesn't put the keystroke into the keyboard buffer.  The defaultπ    handler of that function does nothing and simply returns.  (If yourπ    PC has an older BIOS that doesn't support the extended keyboards,π    INT 15 function 4F is not called.  Early ATs have 84-key keyboards,π    so their BIOS calls INT 15 function 85 but nor 4F.)ππ    Thus your program is free to use SysRq for its own purposes, but atπ    the cost of some programming.  You could hook INT 9, but it'sπ    probably easier to hook INT 15 function 85, which is called whenπ    SysRq is pressed or released.ππQ308. How can my program tell what kind of keyboard is on the system?ππ    Ralf Brown's Interrupt List includes MEMORY.LST, a detailedπ    breakdown by Robin Walker of the contents of the BIOS system blockπ    that starts at 0040:0000.  Bit 4 of byte 0040:0096 is "1=enhancedπ    keyboard installed".  C code to test the keyboard type:π        char far *kbd_stat_byte3 = (char far *)0x00400096UL;π        if (0x10 & *kbd_stat_byte3)π            /* 101- or 102-key keyboard is installed */ππ    {PC Magazine}'s 15 Jan 1991 issue suggests on page 412 that "forπ    some clones [the above test] is not foolproof".  If you use thisπ    method in your program you should provide the user some way toπ    override this test, or at least some way to tell your program toπ    assume a non-enhanced keyboard.  The {PC Magazine} article suggestsπ    a different approach to determining the type of keyboard.ππQ309. How can I tell if input, output, or stderr has been redirected?ππ    Normally, input and output are associated with the console (i.e.,π    with the keyboard and the screen, respectively).  If either is not,π    you know that it has been redirected.  Some source code to checkπ    this is available at the usual archive sites.ππ    If you program in Turbo Pascal, download the /pc/ts/tspa*.zipπ    collection of Turbo Pascal units from garbo; or from Simtel,π    PD1:<MSDOS.TURBOPAS>TSPA*.ZIP.  (Choose TSPA3060.ZIP, TSPA3055.ZIP,π    TSPA3050.ZIP, or TSPA3040.ZIP for Turbo Pascal 6.0, 5.5, 5.0, or 4.0π    respectively.)  Source code is not included.  Also see theπ    information in garbo.uwasa.fi:/pc/ts/tsfaq*.zip Frequently Askedπ    Questions, the Turbo Pascal section.ππ    If you program in C, use isatty( ) if your implementation has it.π    Otherwise, you can download PD1:<MSDOS.SYSUTL>IS_CON10.ZIP fromπ    Simtel; it includes source code.ππ    Good references for the principles are {PC Magazine} 16 Apr 1991π    (vol 10 nr 7) pg 374; Ray Duncan's {Advanced MS-DOS}, ISBNπ    1-55615-157-8, or Ralf Brown's interrupt list for INT 21 functionπ    4400; and Terry Dettman and Jim Kyle's {DOS Programmer's Reference:π    2d edition}, ISBN 0-88022-458-4, pp 602-603.πππIf the posting date is more than six weeks in the past, see instructionsπin part 4 of this list for how to get an updated copy.ππ            Copyright (C) 1992  Stan Brown, Oak Road Systemsπππsection 4.  Disks and filesπ===========================ππQ401. What drive was the PC booted from?ππ    Under DOS 4.0 or later, load 3305 hex into AX; do an INT 21.  DL isπ    returned with an integer indicating the boot drive (1=A:, etc.).ππQ402. How can I boot from drive b:?ππ    Download PD1:<MSDOS.DSKUTL>BOOT_B.ZIP (shareware) from Simtel.  Theπ    included documentation says it works by writing a new boot sector onπ    a disk in your a: drive that redirects the boot to your b: drive.ππQ403. Which real and virtual disk drives are valid?ππ    Use INT 21 function 29 (parse filename).  Point DS:SI at a null-π    terminated ASCII string that contains the drive letter and a colon,π    point ES:DI at a 37-byte dummy FCB buffer, set AX to 2900h, and doπ    an INT 21.  On return, AL is FF if the drive is invalid, somethingπ    else if the drive is valid.  RAM disks and SUBSTed drives areπ    considered valid.ππ    Unfortunately, the b: drive is considered valid even on a single-π    diskette system.  You can check that special case by interrogatingπ    the BIOS equipment byte at 0040:0010.  Bits 7-6 contain the one lessπ    than the number of diskette drives, so if those bits are zero youπ    know that b: is an invalid drive even though function 29 says it'sπ    valid.ππ    Following is some code originally posted by Doug Dougherty, with myπ    fix for the b: special case, tested only in Borland C++ 2.0 (inπ    the small model):ππ        #include <dos.h>π        void drvlist(void)  {π            char *s = "A:", fcb_buff[37];π            int valid;π            for (   ;  *s<='Z';  (*s)++) {π                _SI = (unsigned) s;π                _DI = (unsigned) fcb_buff;π                _ES = _DS;π                _AX = 0x2900;π                geninterrupt(0x21);π                valid = _AL != 0xFF;π                if (*s == 'B'  &&  valid) {π                    char far *equipbyte = (char far *)0x00400010UL;π                    valid = (*equipbyte & (3 << 6)) != 0;π                }π                printf("Drive '%s' is %sa valid drive.\n",π                        s, valid ? "" : "not ");π            }π        }ππQ404. How can I make my single floppy drive both a: and b:?ππ    Under any DOS since DOS 2.0, you can put the commandππ        assign b=aππ    into your AUTOEXEC.BAT file.  Then, when you type "DIR B:" you'll noπ    longer get the annoying prompt to insert diskette B (and the evenπ    more annoying prompt to insert A the next time you type "DIR A:").ππ    You may be wondering why anybody would want to do this.  Suppose youπ    use two different machines, maybe one at home and one at work.  Oneπ    of them has only a 3.5" diskette drive; the other machine has twoπ    drives, and b: is the 3.5" one.  You're bound to type "dir b:" onπ    the first one, and get the nuisance messageππ        Insert diskette for drive B: and press any key when ready.ππ    But if you assign drive b: to point to a:, you avoid this problem.ππ    Caution:  there are a few commands, such as DISKCOPY, that will notπ    work right on ASSIGNed or SUBSTed drives.  See the DOS manual forπ    the full list.  Before typing one of those commands, be sure to turnπ    off the mapping by typing "assign" without arguments.ππ    The DOS 5.0 manual says that ASSIGN is obsolete, and recommends theπ    equivalent form of SUBST: "subst b: a:\".  Unfortunately, if thisπ    command is executed when a: doesn't hold a diskette, the commandπ    fails.  ASSIGN doesn't have this problem, so I must advise you toπ    disregard that particular bit of advice in the DOS manual.ππQ405. Why won't my C program open a file with a path?ππ    You've probably got something like the following code:ππ        char *filename = "c:\foo\bar\mumble.dat";π        . . .  fopen(filename, "r");ππ    The problem is that \f is a form feed, \b is a backspace, and \m isπ    m.  Whenever you want a backslash in a string constant in C, youπ    must use two backslashes:ππ        char *filename = "c:\\foo\\bar\\mumble.dat";ππ    This is a feature of every C compiler, because Dennis Ritchieπ    designed C this way.  It's a problem only on MS-DOS systems, becauseπ    only DOS (and Atari ST/TT running TOS, I'm told) uses the backslashπ    in directory paths.  But even in DOS this backslash conventionπ    applies _only_ to string constants in your source code.  For fileπ    and keyboard input at run time, \ is just a normal character, soπ    users of your program would type in file specs at run time the sameπ    way as in DOS commands, with single backslashes.ππ    Another possibility is to code all paths in source programs with /π    rather than \ characters:ππ        char *filename = "c:/foo/bar/mumble.dat";ππ    Ralf Brown writes that "All versions of the DOS kernel accept eitherπ    forward or backslashes as directory separators.  I tend to use thisπ    form more frequently than backslashes since it is easier to type andπ    read."  This applies to DOS function calls (and therefore to callsπ    to the file library of every programming language), but not to DOSπ    commands.ππQ406. How can I redirect printer output to a file?ππ    My personal favorite utility for this purpose is PRN2FILE from {PCπ    Magazine}, available from Simtel as PD1:<MSDOS.PRINTER>PRN2FILE.ARC,π    or from garbo as prn2file.zip in /pc/printer.  ({PC Magazine} hasπ    given copies away as part of its utilities disks, so you may alreadyπ    have a copy.)ππ    Check the PD1:<MSDOS.PRINTER> directory at Simtel, or /pc/printerπ    at garbo, for lots of other printer-redirection utilities.ππQ407. How can my program open more files than DOS's limit of 20?ππ    (This is a summary of an article Ralf Brown posted on 8 August 1992.)ππ    There are separate limits on files and file handles.  For example,π    DOS opens three files but five file handles:  CON (stdin, stdout,π    and stderr), AUX (stdaux), and PRN (stdprn).ππ    The limit in FILES= in CONFIG.SYS is a system-wide limit on filesπ    opened by all programs (including the three that DOS opens and anyπ    opened by TSRs); each process has a limit of 20 handles (includingπ    the five that DOS opens).  Example:  CONFIG.SYS has FILES=40.  Thenπ    program #1 will be able to open 15 file handles.  Assuming that theπ    program actually does open 15 handles pointing to 15 differentπ    files, other programs could still open a total of 22 files (40-3-15π    = 22), though no one program could open more than 15 file handles.ππ    If you're running DOS 3.3 or later, you can increase the per-processπ    limit of 20 file handles by a call to INT 21 function 67, Set Handleπ    Count.  Your program is still limited by the system-wide limit onπ    open files, so you may also need to increase the FILES= value inπ    your CONFIG.SYS file (and reboot).  The run-time library that you'reπ    using may have a fixed-size table of file handles, so you may alsoπ    need to get source code for the module that contains the table,π    increase the table size, and recompile it.ππQ408. How can I read, create, change, or delete the volume label?ππ    In DOS 5.0 (and, I believe, in 4.0 as well), there are actually twoπ    volume labels: one, the traditional one, is an entry in the rootπ    directory of the disk; and the other is in the boot record alongπ    with the serial number (see next Q).  The DIR and VOL commandsπ    report the traditional label; the LABEL command reports theπ    traditional one but changes both of them.ππ    In DOS 4.0 and later, use INT 21 function 69 to access the bootπ    record's serial number and volume label together; see the next Q.ππ    Assume that by "volume label" you mean the traditional one, the oneπ    that DIR and VOL display.  Though it's a directory entry in the rootπ    directory, you can't change it using the newer DOS file-accessπ    functions (3C, 41, 43); instead, use the old FCB-oriented directoryπ    functions.  Specifically, you need to allocate a 64-byte buffer andπ    a 41- byte extended FCB (file control block).  Call INT 21 AH=1A toπ    find out whether there is a volume label.  If there is, AL returns 0π    and you can change the label using DOS function 17 or delete itπ    using DOS function 13.  If there's no volume label, function 1A willπ    return FF and you can create a label via function 16.  Importantπ    points to notice are that ? wildcards are allowed but * are not; theπ    volume label must be space filled not null terminated.ππ    The following MSC 7.0 code worked for me in DOS 5.0; the functionsπ    it uses have been around since DOS 2.0.  The function parameter is 0π    for the current disk, 1 for a:, 2 for b:, etc.  It doesn't matterπ    what your current directory is; these functions always search theπ    root directory for volume labels.  (I didn't try to change theπ    volume label of any networked drives.)ππ    // Requires DOS.H, STDIO.H, STRING.Hπ    void vollabel(unsigned char drivenum) {π        static unsigned char extfcb[41], dta[64], status, *newlabel;π        int chars_got = 0;π        #define DOS(buff,func) __asm { __asm mov dx,offset buff \π            __asm mov ax,seg buff  __asm push ds  __asm mov ds,ax \π            __asm mov ah,func  __asm int 21h  __asm pop ds \π            __asm mov status,al }π        #define getlabel(buff,prompt) newlabel = buff;  \π            memset(newlabel,' ',11);  printf(prompt);   \π            scanf("%11[^\n]%n", newlabel, &chars_got);  \π            if (chars_got < 11) newlabel[chars_got] = ' ';ππ        // Set up the 64-byte transfer area used by function 1A.π        DOS(dta, 1Ah)π        // Set up an extended FCB and search for the volume label.π        memset(extfcb, 0, sizeof extfcb);π        extfcb[0] = 0xFF;             // denotes extended FCBπ        extfcb[6] = 8;                // volume-label attribute bitπ        extfcb[7] = drivenum;         // 1=A, 2=B, etc.; 0=current driveπ        memset(&extfcb[8], '?', 11);  // wildcard *.*π        DOS(extfcb,11h)π        if (status == 0) {            // DTA contains volume label's FCBπ            printf("volume label is %11.11s\n", &dta[8]);π            getlabel(&dta[0x18], "new label (\"delete\" to delete): ");π            if (chars_got == 0)π                printf("label not changed\n");π            else if (strncmp(newlabel,"delete     ",11) == 0) {π                DOS(dta,13h)π                printf(status ? "label failed\n" : "label deleted\n");π            }π            else {                    // user wants to change labelπ                DOS(dta,17h)π                printf(status ? "label failed\n" : "label changed\n");π            }π        }π        else {                        // no volume label was foundπ            printf("disk has no volume label.\n");π            getlabel(&extfcb[8], "new label (<Enter> for none): ");π            if (chars_got > 0) {π                DOS(extfcb,16h)π                printf(status ? "label failed\n" : "label created\n");π            }π        }π    }   // end function vollabelππQ409. How can I get the disk serial number?ππ    Use INT 21.  AX=6900 gets the serial number; AX=6901 sets it.  Seeπ    Ralf Brown's interrupt list, or page 496 of the July 1992 {PCπ    Magazine}, for details.ππ    This function also gets and sets the volume label, but it's theπ    volume label in the boot record, not the volume label that a DIRπ    command displays.  See the preceding Q.ππQ410. What's the format of .OBJ, .EXE., .COM files?ππ    Please see section 2, "Compile and link".πππsection 5. Serial ports (COM ports)π===================================ππQ501. How do I set my machine up to use COM3 and COM4?ππ    Unless your machine is fairly old, it's probably already set up.π    After installing the board that contains the extra COM port(s),π    check the I/O addresses in word 0040:0004 or 0040:0006.  (In DEBUG,π    type "D 40:4 L4" and remember that every word is displayed lowπ    byte first, so if you see "03 56" the word is 5603.)  If thoseπ    addresses are nonzero, your PC is ready to use the ports and youπ    don't need the rest of this answer.ππ    If the I/O address words in the 0040 segment are zero after you'veπ    installed the I/O board, you need some code to store these valuesπ    into the BIOS data segment:ππ        0040:0004  word  I/O address of COM3π        0040:0006  word  I/O address of COM4π        0040:0011  byte (bits 3-1): number of serial ports installedππ    The documentation with your I/O board should tell you the portπ    addresses.  When you know the proper port addresses, you can addπ    code to your program to store them and the number of serial portsπ    into the BIOS data area before you open communications.  Or you canπ    use DEBUG to create a little program to include in your AUTOEXEC.BATπ    file, using this script:ππ            n SET_ADDR.COM      <--- or a different name ending in .COMπ            a 100π            mov  AX,0040π            mov  DS,AXπ            mov  wo [0004],aaaa <--- replace aaaa with COM3 address or 0π            mov  wo [0006],ffff <--- replace ffff with COM4 address or 0π            and  by [0011],f1π            or   by [0011],8    <--- use number of serial ports times 2π            mov  AH,0π            int  21π                                <--- this line must be blankπ            rCXπ            1fπ            rBXπ            0π            wπ            qππQ502. How do I find the I/O address of a COM port?ππ    Look in the four words beginning at 0040:0000 for COM1 through COM4.π    (The DEBUG command "D 40:0 L8" will do this.  Remember that wordsπ    are stored and displayed low byte first, so a word value of 03F8π    will be displayed as F8 03.)  If the value is zero, that COM port isπ    not installed (or you've got an old BIOS; see the preceding Q).  Ifπ    the value is nonzero, it is the I/O address of the transmit/receiveπ    register for the COM port.  Each COM port occupies eight consecutiveπ    I/O addresses (though only seven are used by many chips).ππ    Here's some C code to find the I/O address:ππ        unsigned ptSel(unsigned comport) {π            unsigned io_addr;π            if (comport >= 1  &&  comport <= 4) {π                unsigned far *com_addr = (unsigned far *)0x00400000UL;π                io_addr = com_addr[comport-1];π            }π            elseπ                io_addr = 0;π            return io_addr;π        }ππQ503. But aren't the COM ports always at I/O addresses 3F8, 2F8, 3E8,π      and 2E8?ππ    The first two are usually right (though not always); the last twoπ    are different on many machines.ππQ504. How do I configure a COM port and use it to transmit data?ππ    After hearing several recommendations, I looked at Joe Campbell's {Cπ    Programmer's Guide to Serial Communications}, ISBN 0-672-22584-0,π    and agree that it is excellent.  He gives complete details on howπ    serial ports work, along with complete programs for doing polled orπ    interrupt-driver I/O.  The book is quite thick, and none of it looksπ    like filler.ππ    If Campbell's book is overkill for you, you'll find a good shortπ    description of serial I/O in {DOS 5: A Developer's Guide}, ISBNπ    1-55851-177-6, by Al Williams.ππ    You may also want to look at an extended example in Borland'sπ    TechFax TI445, part of PD1:<MSDOS.TURBO-C> at Simtel.  Thoughπ    written by Borland, much of it is applicable to other forms of C,π    and it should give you ideas for other programming languages.ππsection 6. Other hardware questions and problemsπ================================================ππQ601. Which 80x86 CPU is running my program?ππ    According to an article posted by Michael Davidson, Intel's approvedπ    code for distinguishing among 8086, 80286, 80386, and 80486 and forπ    detecting the presence of an 80287 or 80387 is published in theπ    Intel's 486SX processor manual (order number 240950-001).  You canπ    download David Kirschbaum's improved version of this from Simtel asπ    PD1:<MSDOS.SYSUTL>CPUID593.ZIP.ππ    According to an article posted by its author, WCPU041.ZIP knows theπ    differences between DX and SX varieties of 386 and 486 chips, andπ    can also detect a math coprocessor.  It's in PD1:<MSDOS.SYSUTL> atπ    Simtel.ππQ602. How can a C program send control codes to my printer?ππ    If you just fprintf(stdprn, ...), C will translate some of yourπ    control codes.  The way around this is to reopen the printer inπ    binary mode:ππ        prn = fopen("PRN", "wb");ππ    You must use a different file handle because stdprn isn't an lvalue.π    By the way, PRN or LPT1 must not be followed by a colon in DOS 5.0.ππ    There's one special case, Ctrl-Z (ASCII 26), the DOS end-of-fileπ    character.  If you try to send an ASCII 26 to your printer, DOSπ    simply ignores it.  To get around this, you need to reset theπ    printer from "cooked" to "raw" mode.  Microsoft C users must use intπ    21 function 44, "get/set device information".  Turbo C and Borlandπ    C++ users can use ioctl to accomplish the same thing:ππ        ioctl(fileno(prn), 1, ioctl(fileno(prn),0) & 0xFF | 0x20, 0);ππ    An alternative approach is simply to write the printer output into aπ    disk file, then copy the file to the printer with the /B switch.ππ    A third approach is to bypass DOS functions entirely and use theπ    BIOS printer functions at INT 17.  If you also fprintf(stdprn,...)π    in the same program, you'll need to use fflush( ) to synchronizeπ    fprintf( )'s buffered output with the BIOS's unbuffered.ππ    By the way, if you've opened the printer in binary mode from a Cπ    program, remember that outgoing \n won't be translated to carriageπ    return/line feed.  Depending on your printer, you may need to sendπ    explicit \n\r sequences.ππQ603. How can I redirect printer output to a file?ππ    Please see section 4, "Disks and files", for the answer.ππQ604. Which video adapter is installed?ππ    The technique below should work if your BIOS is not too old.  Itπ    uses three functions from INT 10, the BIOS video interrupt.  (Ifπ    you're using a Borland language, you may not have to do this theπ    hard way.  Look for a function called DetectGraph or somethingπ    similar.)ππ    Set AH=12h, AL=0, BL=32h; INT 10h.  If AL is 12h, you have a VGA.π    If not, set AH=12h, BL=10h; INT 10h.  If BL is 0,1,2,3, you have anπ    EGA with 64,128,192,256K memory.  If not, set AH=0Fh; INT 10h.  Ifπ    AL is 7, you have an MDA (original monochrome adapter) or Hercules;π    if not, you have a CGA.ππ    I've tested this for my VGA and got the right answer; but I can'tπ    test it for the other equipment types.  Please let me know by emailπ    at brown@ncoast.org if your results vary.ππQ605. How do I switch to 43- or 50-line mode?ππ    Download PD1:<MSDOS.SCREEN>VIDMODE.ZIP from Simtel or one of theπ    mirror sites.  It contains .COM utilities and .ASM source code.ππQ606. How can I find the Microsoft mouse position and button status?ππ    Use INT 33 function 3, described in Ralf Brown's interrupt list.ππ    The Windows manual says that the Logitech mouse is compatible withπ    the Microsoft one, so I assume the interrupt will work the same.ππ    Also, see the directory PD1:<MSDOS.MOUSE> at Simtel.ππQ607. How can I access a specific address in the PC's memory?ππ    First check the library that came with your compiler.  Many vendorsπ    have some variant of peek and poke functions; in Turbo Pascal useπ    the pseudo-arrays Mem, MemW, and MemL.  As an alternative, you canπ    construct a far pointer:  use Ptr in Turbo Pascal, MK_FP in theπ    Turbo C family, and FP_OFF and FP_SEG in Microsoft C.ππ    Caution:  Turbo C and Turbo C++ also have FP_OFF and FP_SEG macros,π    but they can't be used to construct a pointer.  In Borland C++ thoseπ    macros work the same as in Microsoft C, but MK_FP is easier to use.ππ    By the way, it's not useful to talk about "portable" ways to doπ    this.  Any operation that is tied to a specific memory address isπ    not likely to work on another kind of machine.ππQ608. How can I read or write my PC's CMOS memory?ππ    There are a great many public-domain utilities that do this.  Theseπ    were available for download from Simtel as of 31 March 1992:ππ    PD1:<MSDOS.AT>π    CMOS14.ZIP     5965  920817  Saves/restores CMOS to/from fileπ    CMOSER11.ZIP  28323  910721  386/286 enhanced CMOS setup programπ    CMOSRAM.ZIP   76096  920214  Save AT/386/486 CMOS data to file and restoreπ    ROM2.ARC      20497  900131  Save AT and 386 CMOS data to file and restoreπ    SETUP21.ARC   24888  880613  Setup program which modifies CMOS RAMπ    VIEWCMOS.ARC  15374  900225  Display contents of AT CMOS RAM, w/C sourceππ    At garbo, /pc/ts/tsutle17.zip contains a CMOS program to check andπ    display CMOS memory, but not to write to it.ππ    I have heard good reports of CMOS299.ZIP, available in the pc.dirπ    directory of cantva.canterbury.ac.nz [132.181.30.3].ππ    Of the above, my only experience is with CMOSRAM, which seems toπ    work fine.  It contains an excellent (and witty) .DOC file thatπ    explains the hardware involved and gives specific recommendationsπ    for preventing disaster or recovering from it.  It's $5 shareware.ππ    Robert Jourdain's {Programmer's Problem Solver for the IBM PC, XT,π    and AT} has code for accessing the CMOS RAM, according to an articleπ    posted in this newsgroup.ππQ609. How can I access memory beyond 640K?ππ    I'm outside my expertise on this one, but in late 1992 Jamshidπ    Afshar (jamshid@emx.utexas.edu) kindly supplied the following, whichπ    incorporates some corrections agreed with Duncan Murdoch (dmurdoch@π    mast.queensu.ca).  If you have any corrections or comments, pleaseπ    send them to both the above addresses.ππ    ...........................(begin quote)............................π    1. Use XMS or EMS memory.  XMS is preferable in most cases, butπ    some machines won't provide it.  There are some libraries availableπ    at Simtel to access XMS or EMS.  The disadvantage is that youπ    don't allocate the memory as you would with malloc() (or `new' inπ    C++).  I believe it also requires that you lock this memory when inπ    use.  This means your code is not easily ported to other (andπ    future) operating systems and that your code is more convoluted thanπ    it would be under a "real" os.  The advantage is that the libraryπ    works with compilers since Turbo C 2.0 (I think) and that yourπ    program will easily run on even 286s.ππ    2.  Program under MS Windows.  MS Windows functions as a 16-bit DOSπ    Extender (see #3).  Borland/Turbo C++ 3.x includes EasyWin [andπ    Microsoft C/C++ 7.0 has QuickWin --ed.] which is a library thatπ    automatically lets you compile your current code using C/C++π    standard input or <conio.h> into a MS Windows program so your codeπ    can immediately allocate many MBs of memory (Windows enhanced modeπ    even does virtual memory).  The disadvantage is that like any 16-bitπ    Extender a single malloc() is restricted to 64K (unless you want toπ    mess with huge pointers in Windows).  Also, EasyWin's screen outputπ    is significantly slower than a DOS character-mode program's and youπ    must of course run the program from Windows.ππ    3.  Use a 16-bit or 32-bit DOS Extender.  This is definitely theπ    best solution from the programmer's standpoint.  You just allocateπ    as much memory as you need using malloc() or 'new'.  A 16-bitπ    Extender still has 16-bit ints and restricts arrays to 64K, but aπ    32-bit Extender has 32-bits ints (which makes porting a lot of UNIXπ    code easier) so there are no 64K limits.  A 32-bit Extender requiresπ    a 32-bit compiler and the program will not run on 286s.  Someπ    Extenders also do virtual memory.  Using an Extender doesn't requireπ    source code changes and unlike option #1 your code is portable andπ    not obsolete in a few months.  Your options for this solution are:ππ    - Buy PharLap's 16-bit Extender that works with BC++ 3.0+ and MSCπ      (just requires a relink).  Note, the BC++ 3.1 upgrade came withπ      PharLap "lite".  Pharlap's 32-bit Extender works with 32-bitπ      compilers like [?]ππ    - Get the GNU (free,copylefted) gcc 2.x compiler which DJ Delorieπ      ported from UNIX and which uses his 32-bit Extender.  It supportsπ      C and C++, but the Extender is VCPI which means neither theπ      compiler nor programs it produces will run in a DOS session underπ      Windows.  FTP to barnacle.erc.clarkson.edu and getπ      pub/msdos/djgpp/readme.ππ    - Get a 32-bit compiler or one that comes with a DOS Extender.π      Zortech comes with 16-bit and a 32-bit Extenders (no debugger forπ      32-bit programs, but Flashtek sells one).  Watcom also makes a Cπ      [and C++?] 32-bit compiler.  [If anyone else has products or plansπ      to announce, please let me know.]ππ    - Buy Borland Pascal 7.0.  It includes a 16 bit royalty-free DOSπ      extender using the same interface as MS Windows.  It functionsπ      under a DPMI server like Windows or QDPMI from Quarterdeck, andπ      also provides its own server which you can distribute with yourπ      programs.ππ    4.  This option doesn't really count since it's not a solution inπ    DOS, but you could switch to a full 32-bit operating system likeπ    OS/2 2.0 or UNIX (or NT when it comes out).  I believe Win32 willπ    allow you to write 32-bit Windows programs.  [can someone fill me inπ    on what exactly Win32 is?]π    ............................(end quote).............................πππsection 7. Other software questions and problemsπ================================================ππQ701. How can a program reboot my PC?ππ    You can generate a "cold" boot or a "warm" boot.  A cold boot isπ    the same as turning the power off and on; a warm boot is the same asπ    Ctrl-Alt-Del and skips the power-on self test.ππ    For a warm boot, store the hex value 1234 in the word at 0040:0072.π    For a cold boot, store 0 in that word.  Then, if you want to liveπ    dangerously, jump to address FFFF:0000.  Here's C code to do it:ππ        /* WARNING:  data loss possible */π        void bootme(int want_warm)  /* arg 0 = cold boot, 1 = warm */ {π            void (far* boot)(void) = (void (far*)(void))0xFFFF0000UL;π            unsigned far* type = (unsigned far*)0x00400072UL;π            *type = (want_warm ? 0x1234 : 0);π            (*boot)( );π        }ππ    What's wrong with that method?  It will boot right away, withoutπ    closing files, flushing disk caches, etc.  If you boot withoutπ    flushing a write-behind disk cache (if one is running), you couldπ    lose data or even trash your hard drive.ππ    There are two methods of signaling the cache to flush its buffers:π    (1) simulate a keyboard Ctrl-Alt-Del in the keystroke translationπ    function of the BIOS (INT 15 function 4F), and (2) issue a diskπ    reset (DOS function 0D).  Most disk-cache programs hook one or bothπ    of those interrupts, so if you use both methods you'll probably beπ    safe.ππ    When user code simulates a Ctrl-Alt-Del, one or more of the programsπ    that have hooked INT 15 function 4F can ask that the key be ignored byπ    clearing the carry flag.  For example, HyperDisk does this when itπ    has started but not finished a cache flush.  So if the carry flagπ    comes back cleared, the boot code has to wait a couple of cluckπ    ticks and then try again.  (None of this matters on older machinesπ    whose BIOS can't support 101- or 102-key keyboards; see "What is theπ    SysRq key for?" in section 3, "Keyboard".)ππ    Here's C code that tries to signal the disk cache (if any) to flush:ππ        #include <dos.h>π        void bootme(int want_warm)  /* arg 0 = cold boot, 1 = warm */ {π            union REGS reg;π            void    (far* boot)(void) = (void (far*)(void))0xFFFF0000UL;π            unsigned far* boottype    =     (unsigned far*)0x00400072UL;π            char     far* shiftstate  =         (char far*)0x00400017UL;π            unsigned      ticks;π            int           time_to_waste;π            /* Simulate reception of Ctrl-Alt-Del: */π            for (;;) {π                *shiftstate |= 0x0C;    /* turn on Ctrl & Alt */π                reg.x.ax = 0x4F53;      /* 0x53 = Del's scan code */π                reg.x.cflag = 1;        /* sentinel for ignoring key */π                int86(0x15, ®, ®);π                /* If carry flag is still set, we've finished. */π                if (reg.x.cflag)π                    break;π                /* Else waste some time before trying again: */π                reg.h.ah = 0;π                int86(0x1A, ®, ®);/* system time into CX:DX */π                ticks = reg.x.dx;π                for (time_to_waste = 3;  time_to_waste > 0;  ) {π                    reg.h.ah = 0;π                    int86(0x1A, ®, ®);π                    if (ticks != reg.x.dx)π                        ticks = reg.x.dx , --time_to_waste;π                }π            }π            /* Issue a DOS disk reset request: */π            reg.h.ah = 0x0D;π            int86(0x21, ®, ®);π            /* Set boot type and boot: */π            *boottype = (want_warm ? 0x1234 : 0);π            (*boot)( );π        }ππQ702. How can I time events with finer resolution than the systemπ      clock's 55 ms (about 18 ticks a second)?ππ    The following files, among others, can be downloaded from Simtel:ππ    PD1:<MSDOS.AT>π    ATIM.ARC       5946  881126  Precision program timing for ATππ    PD1:<MSDOS.C>π    MILLISEC.ZIP  37734  911205  MSC/asm src for millisecond res timingπ    MSCHRT3.ZIP   53708  910605  High-res timer toolbox for MSC 5.1π    MSEC_12.ZIP    8484  920320  High-def millisec timer v1.2 (C,ASM)π    ZTIMER11.ZIP  77625  920428  Microsecond timer for C, C++, ASMππ    PD1:<MSDOS.TURBO-C>π    TCHRT3.ZIP    53436  910606  High-res timer toolbox for Turbo C 2.0π    TCTIMER.ARC   20087  891030  High-res timing of events for Turbo Cππ    PD1:<MSDOS.TURBOPAS>π    BONUS507.ARC 150435  900205  [Turbo Pascal source: high-res timing]ππ    Pascal users can download source code in /pc/turbopas/bonus507.zipπ    at garbo.ππQ703. How can I find the error level of the previous program?ππ    First, which previou                                                              3      05-28-9313:45ALL                      SWAG SUPPORT TEAM        FREQ1.LST                IMPORT              53          These files are available to file request to anybody listed in theπinternational FidoNet nodelist:ππ!_DATE.ARJ   [   1] David Gegenheimer's Date Routines in PascalπANIVGA11.ARJ [   2] An update to the awsome Animation code for Turbo Pascal 6πBGIDRV.ARJ   [   1] Borland BGI Toolkit BGI driverπBGIFNT.ARJ   [   1] Borland BGI Toolkit BGI FontsπBGISNAP.ARJ  [   1] Screen capture for BGI graphics form BorlandπBUTTEST.ARJ  [   2] Graphical Buttons & Cursors - Includes Pascal SourceπBWAVEINF.ARJ [   1] Structure of files contained in a Bluewave mail packet.π                    Complete Turbo Pascal source.πCHECKIRQ.ARJ [   0] Turbo Pascal Check IRQ for comm port (for AsyncPro)πDATEUNIT.ARJ [   0] Turbo PASCAL date unitπEDITOR.ARJ   [   0] Pascal source for an editor for writing Pascal on lowπ                    memory computersπEPB233.ARJ   [   1] EPB v2.32 formats Pascal source code in a consistent form,π                    with fully automatic indentation. (Includes source)πETASYNCH.ARJ [   0] Asynch routines from FidoNet Pascal Programmers echoπEVOLVE.ARJ   [   0] EVOLVE! Inspect, explore and improve the structure ofπ                    source code in the form of an outline. EVOVLE! can showπ                    you each instance where a symbol is used in a program,π                    without confusing different symbols that are spelled theπ                    same.πFDDEV202.ARJ [   2] Front Door v2.02 developers kitπFGL112A.ARJ  [   1] Fastgraph/Light graphics library v1.12 (1/3)π                    High-performance graphics library for BC++, TC, TC++, MSC,π                    QuickC, Power C, QB, MS FTN, and Turbo Pascal.  Over 140π                    routines, from pixel display to animation tools.πFGL112B.ARJ  [   1] Fastgraph/Light graphics library v1.12 (2/3) User GuideπFGL112C.ARJ  [   1] Fastgraph/Light graphics library v1.12 (3/3) User Guideπ                    examples in 'C'πFGLTPX11.ARJ [   1] Fastgraph/Light graphics library v1.1x (1/1) User Guideπ                    examples in Turbo Pascal 6.0πFLXKEY10.ARJ [   1] Add Registration Key Numbers to Turbo Pascal Programs.π                    Works with Turbo Pascal 4.0-6.0πFONTS.ARJ    [   1] Borland BGI Toolkit FontsπGAMEKIT.ARJ  [   3] More Game routines for TP - includes sourceπGAMETP20.ARJ [   4] Some awesome Turbo Pascal v6.0 units for creating veryπ                    high quality games!πGRAPHSYS.ARJ [   2] TP6.0 graphics unitπIFP1S155.ARJ [   2] Infoplus v1.55  Turbo Pascal and asm source for programπ                    that tells you anything and everything about your hardware.πJPDOOR32.ARJ [   2] Door writing tools for TP5.5 and TP6.0πKTREE31A.ARJ [   2] KeyTree Toolbox v3.1 Disk 1 of 2 A set of library routinesπ                    for Turbo Pascal programmers, which create and maintainπ                    randomly accessed files of variable length records.πKTREE31B.ARJ [   3] KeyTree Toolbox v3.1 Disk 2 of 2πMKMENU.ARJ   [   2] Produce source code for slide bar menus. Works withπ                    Turbo C, Turbo Pascal, dBase, and BASICπMKMSGSRC.ARJ [   0] Turbo Pascal source code for accessing Squish, Hudson, andπ                    *.MSG type message basesπMOUSTL60.ARJ [   0] Mouse Routines For TP6πPASWIZ10.ARJ [   1] Pascal Wizard's Library v1.0 for TPascal 6πPC2VAX.ARJ   [   0] PC to VAX commandline sender (via DECnet) with TP and ASMπ                    sourceπPIBT41S1.ARJ [   0] TURBO Pascal routines which implement a terminal emulationπ                    and host communications program called PibTerm. (1 of 4)πPIBT41S2.ARJ [   0] (2 of 4)πPIBT41S3.ARJ [   0] (3 of 4)πPIBT41S4.ARJ [   0] (4 of 4)πPIBT_DRZ.ARJ [   0] Mods to PIBTERM for compilation under TP6πPNL010.ARJ   [   2] Pascal newsletter #10 with source codeπPROK344.ARJ  [   2] Prokit v3.44 Turbo Pascal 6.0 Door Writing KitπPROTENG.ARJ  [   2] Turbo Pascal Units (5.0, 5.5, 6.0) for file transferπ                    protocols and comm routinesπPROTO100.ARJ [   0] Turbo Pascal source code for some file transferπ        protocolsπRMTP03.ARJ   [   4] Raster Master V2.1: Sprite/graphic editor for Turbo Pascalπ                    5/5.5/6 programmers. Read/Write PCX,ICO,TEGL's DEF.π                    Creates source code that can be included in your programs.π                    Use PutImage to display. Req VGA and Mouse.πSORTTUTR.ARJ [   0] Sort routine demonstration, w/ pascal source Rqrs VGAπSVGABG17.ARJ [   1] Super VGA BGI driver that supports a wide range of VGAπ                    cards and should work on all major brands.πTBTREE16.ARJ [   1] Database routines for Turbo PascalπTPCOMPIL.ARJ [   2] Turbo Pascal Compatible CompilerπTPENV10.ARJ  [   1] TPENV - Routines for manipulating the DOS environment inπ                 PascalπTPFAST40.ARJ [   2] FAST Turbo Pascal Units (with source)πTPTOOL.ARJ   [   1] Tool Kit for Turbo Pascal Compatible CompilerπTPZMODEM.ARJ [   1] Turbo Pascal implementation of ZmodemπTRIDV230.ARJ [   1] Door unit for Turbo Pascal 5.5 and 6.0πTSD-SH.ARJ   [   0] Turbo screen developerπUNZIP21.ARJ  [   1] Source coide in Turbo Pascal and 'C' for unzippingπ                    .ZIP 1.10 filesπVGA256.ARJ   [   1] Borland BGI Toolkit 256 colors MCGA mode.πVGAINTRO.ARJ [   3] Make cool VGA intro screens - source included TP6πVGAPAL10.ARJ [   2] VGApal v1.0 - Complete palette control using TP 6.0. Youπ                    can fade-in and fade-out from black or white, cycleπ                    through any palette colors at will, fade from one colorπ                    to another, switch colors on the fly, plus more!ππHopefully this posting will not offend anyone, it is not posted as aπBBSadvertisement, but as a service to TP programmers.ππFiles are file requestable from 1:3612/220 all hours and days except ZMHπendπ         As well, all of the Pascal Newsletters:ππ PNL001  .ARJ   7552 Pascal Newsletter #1π PNL002  .ARJ  20224 Pascal Newsletter #2π PNL003  .ARJ  43776 Pascal Newsletter #3π PNL004  .ARJ  32000 Pascal Newsletter #4π PNL005  .ARJ  31744 Pascal Newsletter #5π PNL006  .ARJ  62720 Pascal Newsletter #6π PNL010  .ARJ 123520 Pascal Newsletter #10π PNLUPD1 .ARJ    896 Bug Fix for Pascal Newsletter #1ππ         Freq'able from here anytime, from anybody!  And...hopefully I'llπ         be freqing some of your stuff soon!ππ         Later...π                                                                   Markπππππ... Insert Hard Disk #2 and press ENTER to continue installπ--- GEcho 1.00π * Origin: Pascal Paradise --> Pascal Files & More (519)776-4719 (1:246/35.0)π                                                                                                                           4      05-28-9313:45ALL                      SWAG SUPPORT TEAM        PASCAL1.FAQ              IMPORT              28          PASCAL.FAQ             Frequently asked questions about PascalππThe aim of this document is to give answers to frequently askedπquestions in the pascal echo. Thumb rules before asking for help are toπlook in the manuals and in the online help first. Many problems can beπsolved by just looking into either / both of them. Here are someπtopics, that come very often in the Pascal Echo.ππ                                 Part Iπ       #1: Changing the case of stringsπ       #2: Compiler errorsπ       #3: Redirection of outputππ---------------------------------------------------------------------π                               #1 StringsππQ1: How do I access a single char in a string ?πQ2: How can I make a string all upper cases ?ππA1: A string is an Array[0..255] of Char, where the 0th char is theπ    length of the string. To access any character in the string, you canπ    writeππ    MyChar := String[ I ];ππA2: To map a single character to uppercase, you can use the UpCase()π    function of the run time library. To turn a whole string into upperπ    cases, just use this function :ππFunction UpperCase( const S : String ) : String;πVar I : Integer;πBeginπ  { first store the length in the result }π  UpperCase[ 0 ] := S[ 0 ]π  { now translate each char in S into a upper case char in UpperCase }π  For I := 1 to Length( S ) doπ    UpperCase[ I ] := UpCase( S[ I ]);πEnd;ππThere is a assembler implementation in the manuals ( the linkingπassembly language chaprt ), and there are many other optimized upperπcase routines out there.ππ---------------------------------------------------------------------π                           #2 Compiler ErrorsππQ1: I get a "Code segment too large" error. How can I fix it ?πQ2: I get a "Data segment too large" error. How can I fix it ?ππA1: This error means, that you have more than 64K code in one partπ    of your program. To reduce the size of this code segment, you needπ    to move parts of it into other units. This is possible to virtuallyπ    unlimited units.ππA2: This error means, that you have more than 64K data in your program.π    You need to put some data on the heap ( -> GetMem / FreeMem / Newπ    / Dispose ) or to reduce your global data and make it local data onπ    the stack.ππ---------------------------------------------------------------------π                        #3 Redirection of outputππQ1: How can I make the output of my program redirectable under DOS ?ππA1: In general, the output of TP programs _is_ redirectable, except ifπ    you use the CRT unit. Then you need to either reassign output toπ    '' or to declare a Text variable called for example ReOutput ( forπ    Redirectable Output ), and write the output to it.ππExample :ππUses CRT;ππBeginπ  WriteLn( 'This will always show up. Just a copyright.' );π  Assign( Output, '' );π  Rewrite( Output );π  WriteLn( 'This is redirectable.' );π  AssignCRT( Output );π  Rewrite( Output );π  WriteLn( 'And this will alyways show up again.' );πEnd.ππThere are some myths that setting DirectVideo to False would result inπredirectable output even when using CRT, or that TP _always_ writesπdirectly to the screen, and that TP output is _never_ redirectable. Youπcan ignore thos myths, TP writes to the screen using DOS, _except_ ifπyou use the unit CRT. Then TP writes directly to the screen. If you setπthe variable DirectVideo to False, TP uses BIOS calls to write to theπscreen.π